package com.tcpudp.service;

import com.tcpudp.model.Connection;
import com.tcpudp.model.ServerConfig;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.DatagramPacket;
import io.netty.channel.socket.nio.NioDatagramChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.net.InetSocketAddress;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Service
public class UdpServerManager {
    private static final Logger log = LoggerFactory.getLogger(UdpServerManager.class);
    
    private final Map<String, Channel> serverChannels = new ConcurrentHashMap<>();
    private final Map<String, ServerConfig> servers = new ConcurrentHashMap<>();
    private final Map<String, InetSocketAddress> clientAddresses = new ConcurrentHashMap<>();
    private final ConnectionService connectionService;
    private final WebSocketService webSocketService;

    public UdpServerManager(ConnectionService connectionService, WebSocketService webSocketService) {
        this.connectionService = connectionService;
        this.webSocketService = webSocketService;
    }

    public ServerConfig createServer(ServerConfig config) {
        servers.put(config.getId(), config);
        return config;
    }

    public void startServer(String serverId) {
        ServerConfig config = servers.get(serverId);
        if (config == null || config.isRunning()) {
            return;
        }

        EventLoopGroup group = new NioEventLoopGroup();

        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(group)
                    .channel(NioDatagramChannel.class)
                    .option(ChannelOption.SO_BROADCAST, true)
                    .handler(new UdpServerHandler(serverId, config, connectionService, clientAddresses));

            ChannelFuture future = bootstrap.bind(config.getPort()).sync();
            serverChannels.put(serverId, future.channel());
            config.setRunning(true);

            log.info("UDP服务器已启动，端口: {}", config.getPort());
            
            // 通知Web客户端
            webSocketService.broadcastMessage(Map.of(
                "type", "SERVER_STATUS_CHANGED",
                "serverId", serverId,
                "running", true
            ));

            // 异步等待服务器关闭
            future.channel().closeFuture().addListener((ChannelFutureListener) channelFuture -> {
                group.shutdownGracefully();
            });
        } catch (Exception e) {
            log.error("启动UDP服务器失败: {}", e.getMessage());
            group.shutdownGracefully();
        }
    }

    public void stopServer(String serverId) {
        ServerConfig config = servers.get(serverId);
        if (config == null || !config.isRunning()) {
            return;
        }

        Channel channel = serverChannels.get(serverId);
        if (channel != null) {
            channel.close();
            serverChannels.remove(serverId);
        }

        config.setRunning(false);
        
        // 通知Web客户端
        webSocketService.broadcastMessage(Map.of(
            "type", "SERVER_STATUS_CHANGED",
            "serverId", serverId,
            "running", false
        ));
        
        log.info("UDP服务器已停止，端口: {}", config.getPort());
    }

    public void sendMessage(String connectionId, String message, String contentType) {
        Connection connection = connectionService.getConnection(connectionId);
        if (connection == null) {
            return;
        }

        InetSocketAddress clientAddress = clientAddresses.get(connectionId);
        Channel serverChannel = serverChannels.get(connection.getServerId());
        
        if (clientAddress != null && serverChannel != null && serverChannel.isActive()) {
            ByteBuf byteBuf;
            if ("HEX".equals(contentType)) {
                byteBuf = Unpooled.wrappedBuffer(hexStringToByteArray(message));
            } else {
                byteBuf = Unpooled.wrappedBuffer(message.getBytes());
            }
            
            DatagramPacket packet = new DatagramPacket(byteBuf, clientAddress);
            serverChannel.writeAndFlush(packet);
            
            // 记录发送的消息
            connectionService.addMessage(connectionId, message, "OUTBOUND", contentType);
        }
    }

    private byte[] hexStringToByteArray(String s) {
        int len = s.length();
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                    + Character.digit(s.charAt(i + 1), 16));
        }
        return data;
    }

    public ServerConfig getServer(String serverId) {
        return servers.get(serverId);
    }

    public Map<String, ServerConfig> getAllServers() {
        return servers;
    }

    public void updateServer(ServerConfig config) {
        ServerConfig existingConfig = servers.get(config.getId());
        if (existingConfig != null && existingConfig.isRunning()) {
            stopServer(config.getId());
        }
        servers.put(config.getId(), config);
    }

    public void deleteServer(String serverId) {
        ServerConfig config = servers.get(serverId);
        if (config != null && config.isRunning()) {
            stopServer(serverId);
        }
        servers.remove(serverId);
    }

    // 内部UDP处理器类 - 修改为非静态内部类
    private class UdpServerHandler extends SimpleChannelInboundHandler<DatagramPacket> {
        // 使用外部类的日志对象
        
        private final String serverId;
        private final ServerConfig config;
        private final ConnectionService connectionService;
        private final Map<String, InetSocketAddress> clientAddresses;
        private final Map<String, Connection> connectionByAddress = new ConcurrentHashMap<>();

        public UdpServerHandler(String serverId, ServerConfig config, ConnectionService connectionService,
                               Map<String, InetSocketAddress> clientAddresses) {
            this.serverId = serverId;
            this.config = config;
            this.connectionService = connectionService;
            this.clientAddresses = clientAddresses;
        }

        @Override
        protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket packet) {
            InetSocketAddress sender = packet.sender();
            String addressKey = sender.getHostString() + ":" + sender.getPort();
            
            // 获取或创建连接
            Connection connection = connectionByAddress.get(addressKey);
            if (connection == null) {
                connection = connectionService.addConnection(serverId, sender.getHostString(), sender.getPort());
                connectionByAddress.put(addressKey, connection);
                clientAddresses.put(connection.getId(), sender);
                log.info("UDP客户端已连接: {}:{}", sender.getHostString(), sender.getPort());
            }

            // 处理接收到的数据
            ByteBuf content = packet.content();
            byte[] bytes = new byte[content.readableBytes()];
            content.getBytes(content.readerIndex(), bytes);
            
            // 将字节数组转换为可读格式
            String textContent = new String(bytes);
            String hexContent = bytesToHex(bytes);
            
            // 记录接收到的消息
            connectionService.addMessage(connection.getId(), "TEXT".equals(config.getResponseMode()) ? textContent : hexContent, 
                    "INBOUND", "TEXT".equals(config.getResponseMode()) ? "TEXT" : "HEX");

            // 根据响应模式处理
            if ("ECHO".equals(config.getResponseMode())) {
                ByteBuf echoBuf = Unpooled.copiedBuffer(bytes);
                ctx.writeAndFlush(new DatagramPacket(echoBuf, sender));
                connectionService.addMessage(connection.getId(), "TEXT".equals(config.getResponseMode()) ? textContent : hexContent, 
                        "OUTBOUND", "TEXT".equals(config.getResponseMode()) ? "TEXT" : "HEX");
            } else if ("AUTO".equals(config.getResponseMode()) && config.getResponseContent() != null) {
                ByteBuf response;
                if ("HEX".equals(config.getResponseMode())) {
                    response = Unpooled.wrappedBuffer(hexStringToByteArray(config.getResponseContent()));
                } else {
                    response = Unpooled.wrappedBuffer(config.getResponseContent().getBytes());
                }
                ctx.writeAndFlush(new DatagramPacket(response, sender));
                connectionService.addMessage(connection.getId(), config.getResponseContent(), 
                        "OUTBOUND", "TEXT".equals(config.getResponseMode()) ? "TEXT" : "HEX");
            }
        }

        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
            log.error("UDP处理器异常: {}", cause.getMessage());
        }

        private String bytesToHex(byte[] bytes) {
            StringBuilder sb = new StringBuilder();
            for (byte b : bytes) {
                sb.append(String.format("%02X", b));
            }
            return sb.toString();
        }
        
        private byte[] hexStringToByteArray(String s) {
            int len = s.length();
            byte[] data = new byte[len / 2];
            for (int i = 0; i < len; i += 2) {
                data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                        + Character.digit(s.charAt(i + 1), 16));
            }
            return data;
        }
    }
}